﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;

namespace Benchmark.Db.Base.Connection
{
    public static class TypeHelper
    {
        //http://stackoverflow.com/questions/457676/c-reflection-check-if-a-class-is-derived-from-a-generic-class
        //usage: IsSubclassOfRawGeneric(typeof(Entity<>), typeof(Member));
        public static bool IsSubclassOfRawGeneric(Type generic, Type toCheck)
        {
            while (toCheck != typeof(object))
            {
                var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
                if (generic == cur)
                {
                    return true;
                }
                toCheck = toCheck.BaseType;
            }
            return false;
        }

        public static List<Type> GetTypesInFolder(Type baseType, string libraryNameMask)
        {
            List<Type> detectedTypes = new List<Type>();
            string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

            string fileMask = string.Format("{0}.dll", libraryNameMask);
            string[] filePaths = Directory.GetFiles(path, fileMask);
            foreach (string filePath in filePaths)
                try
                {
                    Assembly assembly = Assembly.LoadFile(filePath);

                    Type[] types = assembly.GetTypes();
                    string typeName = baseType.Name;
                    foreach (Type type in types)
                        if (type.IsPublic && type.IsClass)// && !type.IsAbstract)
                            if (type.GetInterface(baseType.FullName) != null || type.IsSubclassOf(baseType))
                                detectedTypes.Add(type);
                }
                catch (ReflectionTypeLoadException rex)
                {
                    Exception[] exceptions = rex.LoaderExceptions;
                    //foreach (Exception exx in exceptions)
                    //    DefaultLogger.Logger.Fatal("LoaderException", exx);
                }
                catch (Exception ex)
                {
                    //DefaultLogger.Logger.DebugFormat("Assembly {0} can't loaded. {1}", filePath, ex);
                    throw;
                }
                finally
                {
                }

            return detectedTypes;
        }

        private static Type FindType(Assembly assembly, string assemblies)
        {
            return assembly.GetType(assemblies);
        }

        public static Type FindType(string fullClassName)
        {
            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
            foreach (Assembly assem in assemblies)
            {
                Type targetType = TypeHelper.FindType(assem, fullClassName);
                if (targetType != null)
                    return targetType;
            }

            return null;
        }
    }
}
